"""" 
Copyright 2009 Texas A&M University
 
Licensed under the Apache License, Version 2.0 (the "License"); you may not use 
this file except in compliance with the License. You may obtain a copy of the 
License at

http://www.apache.org/licenses/LICENSE-2.0
  
Unless required by applicable law or agreed to in writing, software distributed 
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
CONDITIONS OF ANY KIND, either express or implied. See the License for the 
specific language governing permissions and limitations under the License.
"""
import re
from copy import copy
from logging import getLogger

from zope.interface import implements

from zope.component import getGlobalSiteManager

from lxml import etree

from meercat.base.metadata import Metadata
from meercat.base.registry import OrderedRegistry
from meercat.interfaces import IMetadata
from meercat.mapreduce import interfaces
from meercat.mapreduce.exceptions import *
from meercat.mapreduce.reducers.utils import setReduction

from meercat.solr.mapreduce.interfaces import ISolrReducer, ISolrFieldReducer



log = getLogger('meercat.mapreduce.reducers.solr')
registry = getGlobalSiteManager()

class SolrReducer(object):
    implements(ISolrReducer)
    
    preprocessors = []
    postprocessors = []
    
    def __init__(self, defaultReduction=setReduction, formats=('solr',)):
        self.defaultReduction = defaultReduction
        
        self.preprocessors = OrderedRegistry()
        self.postprocessors = OrderedRegistry()
        self.formats = formats
    
    def getFormats(self):
        return self.formats
    
    def reduce(self, *metadata):
        log.debug('%s.reduce(%s)' % (str(self),str(metadata)))
        root = etree.Element('doc')
        format = ''
        
        if len(metadata) > 0:
            format = metadata[0].getFormat()
        
        data = {}
        
        for m in metadata:
            if not m.getValue():
                continue
            m = etree.fromstring(m.getValue())
            for field in m.xpath('//doc/field'):
                if field.get('name'):
                    data.setdefault(field.get('name'),[]).append(field.text)
        
        for processor in self.preprocessors:
            log.debug('%s applying preprocessor' % (str(self),))
            processor(data)
        
        cleaned = {}
        
        for k, v in data.iteritems():
            try:
                r = registry.queryUtility(provided=ISolrFieldReducer, name=k,
                                          default=self.defaultReduction)
                if r:
                    cleaned[k] = r(v)
                else:
                    cleaned[k] = v
                
            except Exception, e:
                log.exception('Exception while reducing field %s=%s' % (str(k), str(v), ))
        
        del data
        
        for processor in self.postprocessors:
            log.debug('%s applying postprocessor: %s' % (str(self),))
            processor(cleaned)
        
        for k, v in cleaned.iteritems():
            for value in v:
                e = etree.Element('field', attrib={'name':k})
                e.text = value
                root.append(e)
        
        del cleaned
        
        output_value = etree.tostring(root,
                                      encoding='utf-8').replace('\n','').strip()
        
        del root
        
        #log.debug(output_value)
        
        return Metadata(source=u'SolrReducer',
                        format=format,
                        value=output_value)
